home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / vdub / source / vdub.cpp < prev   
Encoding:
C/C++ Source or Header  |  2006-05-03  |  6.4 KB  |  243 lines

  1. #include <windows.h>
  2. #include <malloc.h>
  3. #include <tchar.h>
  4. #include <stdio.h>
  5.  
  6. #ifdef _M_AMD64
  7.     #define APPNAME "Veedub64.exe"
  8. #else
  9.     #define APPNAME "VirtualDub.exe"
  10. #endif
  11.  
  12. struct CopyHandles {
  13.     CRITICAL_SECTION *pWriteLock;
  14.     HANDLE hRead;
  15.     HANDLE hWrite;
  16. };
  17.  
  18. DWORD WINAPI CopyThread(LPVOID p) {
  19.     CopyHandles ch = *(const CopyHandles *)p;
  20.     char buf[256];
  21.  
  22.     for(;;) {
  23.         DWORD actual;
  24.         if (!ReadFile(ch.hRead, buf, 256, &actual, NULL))
  25.             break;
  26.  
  27.         if (ch.pWriteLock)
  28.             EnterCriticalSection(ch.pWriteLock);
  29.         BOOL writeOk = WriteFile(ch.hWrite, buf, actual, &actual, NULL);
  30.         if (ch.pWriteLock)
  31.             LeaveCriticalSection(ch.pWriteLock);
  32.         if (!writeOk)
  33.             break;
  34.     }
  35.  
  36.     return 0;
  37. }
  38.  
  39. DWORD g_dwAppThread;
  40. CRITICAL_SECTION g_writeLock;
  41. bool g_bAbortCaught;
  42.  
  43. BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
  44.     static const char abortMsg[]="Attempting to abort, please wait....\r\n";
  45.     EnterCriticalSection(&g_writeLock);
  46.     DWORD actual;
  47.     WriteFile(GetStdHandle(STD_ERROR_HANDLE), abortMsg, sizeof(abortMsg)-1, &actual, NULL);
  48.     LeaveCriticalSection(&g_writeLock);
  49.  
  50.     g_bAbortCaught = true;
  51.  
  52.     if (g_dwAppThread) {
  53.         PostThreadMessage(g_dwAppThread, WM_QUIT, 0, 0);
  54.         return TRUE;
  55.     }
  56.  
  57.     return FALSE;
  58. }
  59.  
  60. BOOL WINAPI SilentCtrlHandler(DWORD dwCtrlType) {
  61.     g_bAbortCaught = true;
  62.     return TRUE;
  63. }
  64.  
  65. bool WereWeRunFromExplorer() {
  66.     // try to guess whether we were run from Explorer:
  67.     //
  68.     // 1) cursor starts at top-left
  69.     //
  70.     CONSOLE_SCREEN_BUFFER_INFO conInfo;
  71.     if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &conInfo))
  72.         return false;
  73.  
  74.     if (conInfo.dwCursorPosition.X || conInfo.dwCursorPosition.Y)
  75.         return false;
  76.  
  77.     return true;
  78. }
  79.  
  80. int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
  81.     TCHAR exepath[MAX_PATH];
  82.     TCHAR exepath2[MAX_PATH];
  83.     TCHAR *fname;
  84.  
  85.     GetModuleFileName(NULL, exepath, MAX_PATH);
  86.     GetFullPathName(exepath, MAX_PATH, exepath2, &fname);
  87.     lstrcpy(fname, _T(APPNAME));
  88.  
  89.     HANDLE hOutputPipeRead;
  90.     HANDLE hOutputPipeWrite;
  91.     HANDLE hErrorPipeRead = NULL;
  92.     HANDLE hErrorPipeWrite = NULL;
  93.     HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  94.     HANDLE hStdError = GetStdHandle(STD_ERROR_HANDLE);
  95.  
  96.     bool bRunFromExplorer = WereWeRunFromExplorer();
  97.  
  98.     SECURITY_ATTRIBUTES sa={
  99.         sizeof(SECURITY_ATTRIBUTES), NULL, TRUE
  100.     };
  101.  
  102.     if (!CreatePipe(&hOutputPipeRead, &hOutputPipeWrite, &sa, 0))
  103.         return 5;
  104.  
  105.     if (hStdError != hStdOut) {
  106.         if (!CreatePipe(&hErrorPipeRead,  &hErrorPipeWrite, &sa, 0))
  107.             return 5;
  108.     }
  109.  
  110.     InitializeCriticalSection(&g_writeLock);
  111.  
  112.     CopyHandles chOutput = { &g_writeLock, hOutputPipeRead, hStdOut };
  113.     CopyHandles chError = { &g_writeLock, hErrorPipeRead, hStdError };
  114.  
  115.     DWORD dwOutputThread, dwErrorThread;
  116.     HANDLE hOutputThread = CreateThread(NULL, 65536, CopyThread, &chOutput, 0, &dwOutputThread);
  117.     HANDLE hErrorThread = NULL;
  118.     
  119.     if (hErrorPipeRead)
  120.         hErrorThread = CreateThread(NULL, 65536, CopyThread, &chError, 0, &dwErrorThread);
  121.  
  122.     // create command line
  123.     LPTSTR cmdLine = GetCommandLine();
  124.     bool quoted = false;
  125.     while(const TCHAR c = *cmdLine) {
  126.         if (c == '"') {
  127.             quoted = !quoted;
  128.             ++cmdLine;
  129.             continue;
  130.         }
  131.  
  132.         if (!quoted && (c == ' ' || c == '\t'))
  133.             break;
  134.  
  135.         ++cmdLine;
  136.     }
  137.  
  138.     // check if we have anything worthy after the command line; if so, don't do
  139.     // the pause-when-run-from-Explorer, as we may have been launched from a batch
  140.     // file or something else with an empty screen
  141.     LPCTSTR tailEnd = cmdLine;
  142.     while(const TCHAR c = *tailEnd) {
  143.         if (c != ' ' && c != '\t')
  144.             break;
  145.         ++tailEnd;
  146.     }
  147.  
  148.     if (*tailEnd)
  149.         bRunFromExplorer = false;
  150.  
  151.     static const TCHAR magicSwitch[] = _T(" /console /x");
  152.     static const size_t magicSwitchLen = sizeof magicSwitch / sizeof magicSwitch[0] - 1;
  153.     size_t cmdLineLen = lstrlen(cmdLine);
  154.     size_t appNameLen = lstrlen(exepath2);
  155.     LPTSTR newCmdLine = (LPTSTR)alloca(sizeof(TCHAR) * (cmdLineLen + appNameLen + magicSwitchLen + 3));
  156.     LPTSTR p = newCmdLine;
  157.  
  158.     *p++ = '"';
  159.     memcpy(p, exepath2, sizeof(TCHAR) * appNameLen);
  160.     p += appNameLen;
  161.     *p++ = '"';
  162.     memcpy(p, magicSwitch, sizeof(TCHAR) * magicSwitchLen);
  163.     p += magicSwitchLen;
  164.     memcpy(p, cmdLine, sizeof(TCHAR) * (cmdLineLen + 1));
  165.  
  166.     // create Ctrl+C handler
  167.     SetConsoleCtrlHandler(CtrlHandler, TRUE);
  168.  
  169.     // kill error dialogs
  170.     UINT dwOldErrorMode = SetErrorMode(0);
  171.     SetErrorMode(dwOldErrorMode | SEM_FAILCRITICALERRORS);
  172.  
  173.     // launch main VirtualDub exe
  174.     STARTUPINFO si = {sizeof(STARTUPINFO)};
  175.     si.wShowWindow    = SW_SHOWMINNOACTIVE;
  176.     si.hStdInput    = CreateFile(_T("nul"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  177.     si.hStdOutput    = hOutputPipeWrite;
  178.     si.hStdError    = hErrorPipeWrite;
  179.     si.dwFlags        = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
  180.     PROCESS_INFORMATION pi;
  181.  
  182.     DWORD rc = 20;
  183.  
  184.     if (CreateProcess(exepath2, newCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
  185.         CloseHandle(pi.hThread);
  186.  
  187.         g_dwAppThread = pi.dwThreadId;
  188.         WaitForSingleObject(pi.hProcess, INFINITE);
  189.         g_dwAppThread = 0;
  190.  
  191.         GetExitCodeProcess(pi.hProcess, &rc);
  192.  
  193.         CloseHandle(pi.hProcess);
  194.     } else {
  195.         TCHAR *msg;
  196.  
  197.         if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPTSTR)&msg, 0, NULL)) {
  198.             static const TCHAR pretext[]=_T("Cannot launch ") _T(APPNAME) _T(": ");
  199.             DWORD actual;
  200.             WriteFile(hStdOut, pretext, sizeof pretext / sizeof pretext[0] - 1, &actual, NULL);
  201.             WriteFile(hStdOut, msg, lstrlen(msg), &actual, NULL);
  202.             LocalFree((HLOCAL)msg);
  203.         }
  204.     }
  205.  
  206.     if (g_bAbortCaught && !rc)
  207.         rc = 5;
  208.  
  209.     // close pipes first to break any blocking console I/O call in the main
  210.     // app
  211.     CloseHandle(hOutputPipeWrite);
  212.     if (hErrorPipeWrite)
  213.         CloseHandle(hErrorPipeWrite);
  214.  
  215.     // wait for VirtualDub to terminate; use alertable wait so we see Ctrl+C
  216.     WaitForSingleObjectEx(hOutputThread, INFINITE, TRUE);
  217.  
  218.     // swap Ctrl+C handlers
  219.     SetConsoleCtrlHandler(CtrlHandler, FALSE);
  220.     SetConsoleCtrlHandler(SilentCtrlHandler, TRUE);
  221.  
  222.     if (hErrorThread)
  223.         WaitForSingleObject(hErrorThread, INFINITE);
  224.  
  225.     CloseHandle(hOutputThread);
  226.     if (hErrorThread)
  227.         CloseHandle(hErrorThread);
  228.  
  229.     CloseHandle(hOutputPipeRead);
  230.     if (hErrorPipeRead)
  231.         CloseHandle(hErrorPipeRead);
  232.  
  233.     DeleteCriticalSection(&g_writeLock);
  234.  
  235.     // if we were launched from Explorer, wait for close
  236.     if (bRunFromExplorer) {
  237.         while(!g_bAbortCaught)
  238.             SleepEx(100, TRUE);
  239.     }
  240.  
  241.     return (int)rc;
  242. }
  243.